if (!Logger) var Logger = {
    DEBUG : 4,
    INFO : 3,
    WARN : 2,
    ERROR : 1,
    level : Logger.DEBUG,
    writeMessage : function (prefix, caller, obj, color) {
        var div = getDiv ();
        var line = document.createElement ("span");

        function getDate (showMillsecond) {
            var date = new Date ();
            var s = "";
            s += date.getFullYear();
            s += "-";
            var m = date.getMonth () + 1;
            s += m < 10 ? "0" + m : "" + m;
            s += "-";
            s += date.getDate () < 10 ? "0" + date.getDate () : "" + date.getDate ();
            s += " ";
            s += date.getHours () < 10 ? "0" + date.getHours () : "" + date.getHours ();
            s += ":";
            s += date.getMinutes () < 10 ? "0" + date.getMinutes () : "" + date.getMinutes ();
            s += ":";
            s += date.getSeconds () < 10 ? "0" + date.getSeconds () : "" + date.getSeconds ();
            if (showMillsecond) {
                s += ".";
                var ms = date.getMilliseconds ();
                if (ms < 10) s += "00" + ms;
                else if (ms < 100) s += "0" + ms;
                else s += ms;
            }
            return s;
        }

        function getDiv () {
            var div = document.getElementById ("debug");
            if (!div) {
                div = document.createElement ("div");
                div.id = 'debug';
                document.body.appendChild (div);
                div.style.fontFamily = "Courier New";
                div.style.fontSize = 12;
                div.style.width = "100%";
                div.style.overflow = 'auto';
                div.style.border = "1px solid black";
                div.style.backgroundColor = "lightyellow";
                div.style.textAlign = 'left';
            }
            return div;
        }

        var date_string = getDate(true);
        line.style.color = color;
        var text = (obj == null) ? "null" : obj.toString ();
        var i;
        if (text.indexOf ("\n") != -1) {
            var lines = text.split ("\n");
            text = "";
            for (i = 0; i < lines.length; i ++)
            {
                if (i != 0) text += "<br>";
                text += lines[i].replace (/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace (/</, '&lt;').replace (/>/, '&gt;');
            }
        }
        else
            text = text.replace (/</g, '&lt;').replace (/>/g, '&gt;');
        line.innerHTML = '[' + getDate(true) + '][' + prefix + '][' + caller + '] ' + text;
        div.appendChild (line);
        div.appendChild (document.createElement ("br"));
        if (typeof (obj) == 'object') {
            var indent = "";
            for (i = 0; i < date_string.length + 10; i ++) indent += "&nbsp;"
            for (var key in obj) {
                var value = obj [key];
                if (typeof (value) == 'function') continue;
                line = document.createElement ("span");
                line.style.color = color;
                line.innerHTML = indent + key + " -> " + obj [key] + "<br>";
                div.appendChild (line);
            }
        }
    },
    debug : function (obj) {
        if (this.level && this.level >= this.DEBUG)
            this.writeMessage ('DEBUG', __getCaller (this.debug), obj, '#996600');
    },
    info : function (obj) {
        if (this.level && this.level >= this.INFO)
            this.writeMessage (' INFO', __getCaller (this.info), obj, 'black');
    },
    warn : function (obj) {
        if (this.level && this.level >= this.WARN)
            this.writeMessage (' WARN', __getCaller (this.warn), obj, 'orange');
    },
    error : function (obj) {
        if (this.level >= this.ERROR)
            this.writeMessage ('FATAL', __getCaller (this.error), obj, 'red');
    },
    noop : function () { this.writeMessage ('NOOP', __getCaller (this.noop), '', 'black'); }
};
/*
if (!Logger.writeMessage)
{
	Logger.writeMessage =
}

Logger.DEBUG = 4;
Logger.INFO  = 3;
Logger.WARN  = 2;
Logger.ERROR = 1;

Logger.level = Logger.DEBUG;

if (!Logger.debug) {
	Logger.debug = function (obj) {
		if (Logger.level && Logger.level >= Logger.DEBUG)
			Logger.writeMessage ('DEBUG', __getCaller (Logger.debug), obj, '#996600');
	}
}

if (!Logger.info) {
	Logger.info = function (obj) {
		if (Logger.level && Logger.level >= Logger.INFO)
		Logger.writeMessage (' INFO', __getCaller (Logger.info), obj, 'black');
	}
}

if (!Logger.warn) {
	Logger.warn = function (obj) {
		if (Logger.level && Logger.level >= Logger.WARN)
		Logger.writeMessage (' WARN', __getCaller (Logger.warn), obj, 'orange');
	}
}

if (!Logger.error) {
	Logger.error = function (obj) {
		if (Logger.level >= Logger.ERROR)
		Logger.writeMessage ('FATAL', __getCaller (Logger.error), obj, 'red');
	}
}

if (!Logger.noop) {
	Logger.noop = function () { Logger.writeMessage ('NOOP', '', 'black'); }
}

if (!Logger.getDiv) {
	Logger.getDiv = function () {
		var div = document.getElementById ("debug");
		if (!div) {
			div = document.createElement ("div");
			div.id = 'debug';
			document.body.appendChild (div);
			div.style.fontFamily = "Courier New";
			div.style.fontSize = 12;
			div.style.width = "100%";
			div.style.overflow = 'auto';
			div.style.border = "1px solid black";
			div.style.backgroundColor = "lightyellow";
            div.style.textAlign = 'left';
		}
		return div;
	}
}
*/

function __getCaller (func) {
	if (!func) return null;
	return func.caller.name;
}